/*
 * Gluon.h
 *
 *  Created on: 11.03.2012
 *      Author: ignacio
 */

#ifndef GLUON_H_
#define GLUON_H_
#include "Character.h"
#include "MovementBehaviour.h"

namespace neurignacio{
/*
 * **************************************************************************************************************************************
 * 															BEHAVIOUR PARTICLES															*
 * **************************************************************************************************************************************
 */
/*
 * *******
 * Gluon *
 * *******
 */
class Gluon : public Muon
// Neutron is a Muon with virtual movement behaviour
{
#define EPSILON_CONSTANT 1e-6f	// By Default, each epsilon parameter will be calculated as EPSILON_CONSTANT*maxAcceleration
public:
	MovementBehaviourPointerContainer movementBehaviour; // Points to the current movement behaviour. It can be an array as well
	SteeringOutput steering;		// Stores the current Steering
	SteeringOutput initialSteering; 	// Stores a external Steering that applies the character (i.e. coming from group behaviour)
	real linearEpsilon;		// if steering.linear.length() < linearEpsilon => steering is considered zero
	angle angularEpsilon;	// if steering.angular < angularEpsilon => steering is considered zero
protected:
	void trim();
public:
	Gluon(void): Muon(), movementBehaviour(), steering(), initialSteering(), linearEpsilon(0), angularEpsilon(NULL_ANGLE) {}
	Gluon(const Gluon& gluon) : Muon(static_cast<Muon>(gluon)), movementBehaviour(gluon.movementBehaviour), steering(gluon.steering), initialSteering(gluon.initialSteering), linearEpsilon(gluon.linearEpsilon), angularEpsilon(gluon.angularEpsilon) {}
	Gluon& operator=(const Gluon& other)
	{
		if (this!=&other) {static_cast<Muon>(*this)=static_cast<Muon>(other); movementBehaviour=other.movementBehaviour; steering=other.steering; initialSteering=other.initialSteering; linearEpsilon=other.linearEpsilon; angularEpsilon=other.angularEpsilon;} return *this;
	}
	void addMovementBehaviour(MovementBehaviour* behaviour);
	void setMovementBehaviour(MovementBehaviour* behaviour) {addMovementBehaviour(behaviour);} // Synonym for backward compatibility
	void addMovementBehaviour(MovementBehaviourPointerContainer& behaviourArray);
	void getSteering(const SteeringOutput& externalSteering=NULL_STEERING); // Includes Weighted Blending
	void setEpsilonParameters(real linear=0, angle angular=0) {linearEpsilon=(linear?linear:maxAcceleration*EPSILON_CONSTANT); angularEpsilon=(angularEpsilon.isZero()?maxAngularAcceleration*EPSILON_CONSTANT:angularEpsilon);}
	void sortMovementBehaviours();
	int whichMovementBehaviour(const unsigned int& index=0) const;
	void refresh(void);
	friend ostream& operator<<(ostream& out, const Gluon& gluon);
};
typedef BaseContainer<Gluon> GluonContainer;	// Stores a set of Gluons
typedef BasePointerContainer<Gluon> GluonPointerContainer;
} // end namespace neurignacio


#endif /* GLUON_H_ */
